package com.kancy.publicapi.aop.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kancy.publicapi.common.util.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;

/**
 * 基类切面<br>
 *
 * @author kancy
 */
@Slf4j
public abstract class BaseAspect<T> implements ApplicationContextAware {

    /**
     * Spring的ApplicationContext
     * */
    protected ApplicationContext context;

    /**
     * 功能描述: 切面检查<br>
     * 〈功能详细描述〉
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    protected abstract T check(ProceedingJoinPoint joinPoint) throws Throwable;

    /***
     *
     * 功能描述: 统一获取Request<br>
     * 〈功能详细描述〉
     *
     * @return
     */
    protected final HttpServletRequest getRequest() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        return request;
    }

    /***
     *
     * 功能描述: 统一获取Request<br>
     * 〈功能详细描述〉
     *
     * @return
     */
    protected final HttpServletResponse getResponse() {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        return response;
    }


    @Override
    public final void setApplicationContext(ApplicationContext context) throws BeansException {
        this.context = context;
    }

    /**
     * 根据Name定义，获取指定的SpringBean对象
     *
     * @param name
     * @param clazz
     * @return
     */
    public final <T> T getBean(String name, Class<T> clazz) {
        return (T) getBean(name);
    }

    /**
     * 根据Class类型，获取指定的SpringBean对象
     *
     * @param clazz
     * @return
     */
    public final <T> T getBean(Class<T> clazz) {
        try {
            return this.context.getBean(clazz);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据Name定义，获取指定的SpringBean对象
     *
     * @param name
     * @return
     */
    public final Object getBean(String name) {
        if (this.context.containsBean(name)) {
            return this.context.getBean(name);
        }
        return null;
    }

    /**
     * 获取当期Context容器中的全部SpringBean的名称列表
     *
     * @param clazz
     * @return
     */
    public final <T> String[] getBeanNames(Class<T> clazz) {
        return this.context.getBeanNamesForType(clazz);
    }

    /**
     * 获取IP地址的方法
     * @return IP地址
     */
    protected final String getIpAddr() {
        return IPUtils.getRequestIp(getRequest());
    }

    /**
     * 生成参数信息
     *
     * @param joinPoint
     * @return
     */
    protected final Map<String, Object> generateValueMap(ProceedingJoinPoint joinPoint) {
        Map<String, Object> valueMap = new HashMap<String, Object>();
        // 获取当前注解方法
        Object[] args = joinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        for (int i = 0; i < method.getParameters().length; i++) {
            Parameter parameter = method.getParameters()[i];
            if (parameter.getAnnotation(RequestBody.class) != null) {
                JSONObject jsonObject = new JSONObject();
                if (args[i] instanceof String) {
                    jsonObject = JSON.parseObject(args[i].toString());
                } else {
                    jsonObject = JSON.parseObject(JSON.toJSONString(args[i]));
                }
                generateValueMap(valueMap, jsonObject);
            } else {
                valueMap.put(parameter.getName(), args[i]);
            }
        }
        return valueMap;
    }

    /**
     * 生成参数信息
     *
     * @param valueMap
     * @param jsonObject
     */
    protected final void generateValueMap(Map<String, Object> valueMap, JSONObject jsonObject) {
        for (String key : jsonObject.keySet()) {
            Object value = jsonObject.get(key);
            valueMap.put(key, value);
            if (value instanceof JSONObject) {
                generateValueMap(valueMap, jsonObject.getJSONObject(key));
            }
        }
    }

    /**
     * 获取方法注解
     * @param joinPoint
     * @param annotationClass
     * @param <T>
     * @return
     * @throws NoSuchMethodException
     */
    protected final <T extends Annotation> T getMethodAnnotation(ProceedingJoinPoint joinPoint, Class<T> annotationClass)
            throws NoSuchMethodException {
        Class<?> classTarget=joinPoint.getTarget().getClass();
        Class<?>[] paramTypes=((MethodSignature) joinPoint.getSignature()).getParameterTypes();
        Method objMethod=classTarget.getMethod(joinPoint.getSignature().getName(), paramTypes);
        if(!objMethod.isAnnotationPresent(annotationClass)){
            return null;
        }
        return objMethod.getAnnotation(annotationClass);
    }

}